﻿using Cosmos.DataAccess.Trade.HighGate.Internals;
using Cosmos.DataAccess.Trade.HighGate.Internals.Protocol;
using Cosmos.DataAccess.Trade.HighGate.v1.Protocol;
using Cosmos.DataAccess.Trade.v1;
using Cosmos.DataAccess.Trade.v1.Model;
using Cosmos.DataAccess.Trade.v1.Protocol;
using Cosmos.Observability.Application.Contracts.Logger;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;
using Serilog.Parsing;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace Cosmos.DataAccess.Trade.HighGate.v1
{
    public class HighGateProductInfo : IBaseLoginInfo
    {
        /// <summary>
        /// 产品名
        /// </summary>
        public string ProductID { get; set; } = "";

        /// <summary>
        /// 账户名
        /// </summary>
        public string Account { get; set; } = "";

        /// <summary>
        /// 密码
        /// </summary>
        public string PassWord { get; set; } = "";

        /// <summary>
        /// 本次登录token
        /// </summary>
        public string Token { get; set; } = "";

        /// <summary>
        /// 消息中心ip
        /// </summary>
        public string Ip { get; set; } = "10.4.123.112";

        /// <summary>
        /// 消息中心端口
        /// </summary>
        public int Port { get; set; } = 9999;
    }

    /// <summary>
    /// 会话状态
    /// </summary>
    public enum DataSessionStatus
    {
        /// <summary>
        /// 已停止
        /// </summary>
        Stopped = 1,

        /// <summary>
        /// 启动中
        /// </summary>
        StartPending = 2,

        /// <summary>
        /// 停止中
        /// </summary>
        StopPending = 3,

        /// <summary>
        /// 运行中
        /// </summary>
        Running = 4,

        /// <summary>
        /// 唤醒中
        /// </summary>
        ContinuePending = 5,

        /// <summary>
        /// 暂停中
        /// </summary>
        PausePending = 6,

        /// <summary>
        /// 已暂停
        /// </summary>
        Paused = 7
    }

    public class HigateMessageData
    {
        /// <summary>
        /// 请求类型
        /// </summary>
        public ReqType Action { get; set; }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string Content { get; set; }
    }

    /// <summary>
    /// 会话器
    /// </summary>
    public class DataSessionController : IDataSessionController
    {
        //创建session
        [DllImport("LHsession.dll")]
        internal static extern IntPtr CreateMsgCenterApi(IntPtr cb);

        //登录
        [DllImport("LHsession.dll")]
        internal static extern void Login(IntPtr sdkHandle, IntPtr address, int port, IntPtr account, IntPtr password);

        //登录
        [DllImport("LHsession.dll")]
        internal static extern void Send(IntPtr sdkHandle, IntPtr sendstr, int len);

        public DataSessionController(ICosmosLogger cosmosLogger, HighGateProductInfo vendorProductInfo)
        {
            this.cosmosLogger = cosmosLogger;
            TradeStatus = TradeDataSessionStatus.Stopped;
            _vendorProductInfo = vendorProductInfo;
        }

        /// <summary>
        /// 设置账号和token信息
        /// </summary>
        /// <returns></returns>
        public Task SetAccountToken(string account, string token, string password)
        {
            _vendorProductInfo.Account = account;
            _vendorProductInfo.Token = token;
            _vendorProductInfo.PassWord = password;
            return Task.CompletedTask;
        }

        /// <summary>
        /// 保存订阅信息
        /// </summary>
        /// <param name="topic"></param>
        /// <returns></returns>
        public DataPushJob SubScribe(string topic)
        {
            DataSubscription subscription = new DataSubscription()
            {
                Topic = topic,
            };

            DataPushJob dataPushJob = new DataPushJob()
            {
                Subscription = subscription,
                Session = this,
            };

            subscription.PushJob = dataPushJob;
            ChangeSubscription(dataPushJob.Subscription, true);
            return dataPushJob;
        }
        /// <summary>
        /// 启动会话
        /// </summary>
        /// <returns></returns>
        public Task StartAsync()
        {
            DoConnect();

            return Task.CompletedTask;
        }

        /// <summary>
        /// 停止会话
        /// </summary>
        /// <returns></returns>
        public Task StopAsync()
        {
            JObject jsParameter = new JObject();
            jsParameter["action"] = "logout";
            jsParameter["token"] = _vendorProductInfo.Token;
            DataRequest request = new DataRequest()
            {
                method = "client",
                servicename = "",
                parameters = jsParameter,
                token = _vendorProductInfo.Token
            };

            var strRequest = Marshal.StringToCoTaskMemAnsi(request.Serialize());
            string convaertedString = Marshal.PtrToStringAnsi(strRequest);
            int length = convaertedString.Length;
            Send(sdkHandle, strRequest, length);
            return Task.CompletedTask;
        }
        private void _raiseStatusChanged()
        {
            TradeStatusChanged?.Invoke(this, TradeStatus);
        }
        private static IntPtr DelegateToFunction<DelegateType>(DelegateType d)
        {
            return Marshal.GetFunctionPointerForDelegate<DelegateType>(d);
        }

        /// <summary>
        /// 第三方模块请求
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public async Task<IThirdQueryResult> ThirdRequest(IThirdQueryParameters parameters)
        {
            JObject jsParameter = new JObject();
            jsParameter["user"] = _account;
            jsParameter["action"] = parameters.Action;
            jsParameter["data"] = parameters.Parameters;
            DataRequest request = new DataRequest()
            {
                method = "query_data",
                servicename = "rpc.subcenter",
                parameters = jsParameter,
                token = _vendorProductInfo.Token
            };
            DataResponse dataResponse = await SendRequest(request);
            var thirdQueryResult = JsonSerializer.Deserialize<ThirdQueryResult>(dataResponse.response);
            return thirdQueryResult;
        }

        /// <summary>
        /// 第三方模块订阅
        /// </summary>
        /// <param name="subscriberParameters"></param>
        /// <returns></returns>
        public async Task<DataPushJob> ThirdSubsribe(ISubscribeParameters subscriberParameters)
        {
           // JObject jsParameter = new JObject();
            JObject jsParameter = new JObject();
            jsParameter["topic"] = subscriberParameters.topic;
            if(subscriberParameters.req == null)
            {
                jsParameter["req"] = new JArray();
            }
            else
            {
                jsParameter["req"] = JObject.FromObject(subscriberParameters.req);
            }
            DataRequest request = new DataRequest()
            {
                method = "subscribe",
                servicename = "rpc.subcenter",
                parameters = jsParameter,
                token = _vendorProductInfo.Token
            };
            DataResponse dataResponse = await SendRequest(request);
            if(!dataResponse.IsBad)
            {
                var dataPushJob = SubScribe(subscriberParameters.topic);
                return dataPushJob;
            }

            return null;
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<DataResponse> SendRequest(DataRequest request)
        {
            if (sdkHandle.ToInt32() > 0)
            {
                AddActiveRequest(request);
                string strSend = request.Serialize();
                var strRequest = Marshal.StringToCoTaskMemAnsi(strSend);
                string convaertedString = Marshal.PtrToStringAnsi(strRequest);
                int length = convaertedString.Length;
                request.Status.BeforeSendDateTime = DateTime.Now;
                Send(sdkHandle, strRequest, length);
                request.Status.AfterSendDateTime = DateTime.Now;

                if (!request.ResponsedEvent.Wait(600000))
                {
                    RemoveActiveRequest(request);
                    var response = new DataResponse();
                    response.IsTimeOutResponse = true;
                    response.IsBad = true;
                    request.Status.Response = response;
                }
                else
                {
                    request.ResponsedEvent.Dispose();// 释放句柄
                }
                return request.Status.Response;
            }
            else
            {
                var response = new DataResponse();
                response.id = request.id;
                response.IsBad = true;
                return response;
            }
        }

        // 消息回调函数
        public delegate void CallbackDelegate(IntPtr sdkHandle, IntPtr result, int len);

        /// <summary>
        /// 接收到消息
        /// </summary>
        /// <param name="sdkHandle"></param>
        /// <param name="result"></param>
        /// <param name="len"></param>
        private async void CallBack(IntPtr sdkHandle, IntPtr result, int len)
        {
            // 将 IntPtr 转换为字节数组
            byte[] gbkBytes = new byte[len];
            Marshal.Copy(result, gbkBytes, 0, len);

            // 将 GBK 字节数组解码为 UTF-8 字符串
            string gbkString = Encoding.GetEncoding("GBK").GetString(gbkBytes);
            string utf8String = Encoding.UTF8.GetString(Encoding.Convert(Encoding.GetEncoding("GBK"), Encoding.UTF8, gbkBytes));

            var highGateMsgData = JsonSerializer.Deserialize<HigateMessageData>(utf8String);
            if(String.IsNullOrEmpty(highGateMsgData.Content)) return;

            JsonDocument document = JsonDocument.Parse(highGateMsgData.Content);

            DataResponse dataResponse = new DataResponse();
            if (document.RootElement.TryGetProperty("id", out var id))
            {
                dataResponse.id = Guid.Parse(id.GetString());

                if (document.RootElement.TryGetProperty("result", out var results))
                {
                    dataResponse.response = results.GetRawText();
                }
                else
                {
                    dataResponse.IsBad = true;
                    dataResponse.response = document.RootElement.GetProperty("error").GetRawText();
                }
            }
            //处理推送
            else
            {
                if (document.RootElement.TryGetProperty("method", out var method))
                {
                    dataResponse.Topic = method.GetString();

                }
                if (document.RootElement.TryGetProperty("params", out var param))
                {
                    dataResponse.response = param.GetRawText();
                }
            }
            
            if (highGateMsgData == null) return;
            switch (highGateMsgData.Action)
            {
                /// 单独处理登录请求
                case ReqType.RT_SESSION_USER_LOGIN:
                    await HandleLogin(dataResponse);
                    break;
                default:
                    await HandleResponse(dataResponse);
                    break;
            }

        }

        private async Task HandleResponse(DataResponse dataResponse)
        {
            if (dataResponse == null) return;

            ///推送数据
            if(dataResponse.id ==  Guid.Empty)
            {
                await HandlePushMsg(dataResponse);
            }
            ///应答数据
            else
            {
                // 根据Response查找Request
                var req = FindActiveRequest(dataResponse);
                if (req == null)
                {
                    return;
                }
                // 从Active队列里移除Request
                RemoveActiveRequest(req);

                // 请求包
                req.Status.Response = dataResponse;
                req.ResponsedEvent.Set();
            }
        }
        private async Task HandleLogin(DataResponse dataResponse)
        {
            if (dataResponse == null) return;

            if (dataResponse.IsBad) return;


            var loginResult = JsonSerializer.Deserialize<LoginResult>(dataResponse.response);
            if (loginResult == null) return;

            _vendorProductInfo.Token = loginResult.token;
            TradeStatus = TradeDataSessionStatus.Running;
        }

        private async Task HandlePushMsg(DataResponse data_response)
        {
            if(data_response == null) return;
            if(data_response.IsBad) return;

            List<DataPushJob> push_jobs_shadow = new List<DataPushJob>();

            lock (ActivePushJobLock)
            {
                // 找到对应的订阅
                var push_jobs = FindActivePushJobs(data_response);

                if (push_jobs == null)
                {
                    return;
                }
                // 触发其push_job的推送事件

                push_jobs_shadow.AddRange(push_jobs);
            }

            foreach (var push_job in push_jobs_shadow)
            {
                push_job.RaisePushedEvent(data_response);
            }

        }

        private static Dictionary<IntPtr, DataSessionController> _mapCenter = new Dictionary<nint, DataSessionController>();

        private CallbackDelegate _callback;

        private IntPtr _truePtr;

        public void DoConnect()
        {
            _account = _vendorProductInfo.Account + "_" + _vendorProductInfo.ProductID;
            string password = _vendorProductInfo.PassWord + "||" + _vendorProductInfo.Token;
            _callback = new CallbackDelegate(CallBack);
            _truePtr = DelegateToFunction(_callback);

            sdkHandle = CreateMsgCenterApi(_truePtr);
            if (sdkHandle.ToInt32() > 0)
            {
                _mapCenter[sdkHandle] = this;
                Login(sdkHandle, Marshal.StringToCoTaskMemAnsi(_vendorProductInfo.Ip), _vendorProductInfo.Port, Marshal.StringToCoTaskMemAnsi(_account), Marshal.StringToCoTaskMemAnsi(password));
            }
        }

        public IBaseLoginInfo GetBaseInfo()
        {
            return _vendorProductInfo;
        }

        private IntPtr sdkHandle = new IntPtr(0);

        /// <summary>
        /// 会话状态变更事件
        /// </summary>
        public event EventHandler<TradeDataSessionStatus> TradeStatusChanged;

        private string _account { get; set; }

        private ICosmosLogger cosmosLogger { get; set; }

        private HighGateProductInfo _vendorProductInfo { get; set; }

        private TradeDataSessionStatus _tradeStatus { get; set; }

        public TradeDataSessionStatus TradeStatus
        {
            get
            {
                return _tradeStatus;
            }
            set
            {
                _tradeStatus = value;
                _raiseStatusChanged();
            }
        }

        private void AddTimeOutString(string request_string)
        {
            //lock (ActiveRequestsLock)
            //{
           /* TimeOutRequestStrings.Enqueue($"{request_string} time:{DateTime.Now.ToLongTimeString()}");
            TimeOutRequestCount++;
            if (TimeOutRequestStrings.Count > 50)
            {
                TimeOutRequestStrings.Dequeue();
            }*/
            //}
        }

        // 如果服务端返回空包，则登记
        private void AddBadResponseString(string request_string, bool RecordCount = true)
        {
            //lock (ActiveRequestsLock)
            //{
            /*BadResponseRequesStrings.Enqueue($"{request_string} time:{DateTime.Now.ToLongTimeString()}");
            if (RecordCount)
            {
                BadResponseRequestCount++;
            }
            if (BadResponseRequesStrings.Count > 50)
            {
                BadResponseRequesStrings.Dequeue();
            }*/
            //}
        }

        public void StopPushJob(DataPushJob data_push_job)
        {
            ChangeSubscription(data_push_job.Subscription, false);
        }

        private void ChangeSubscription(DataSubscription user_subscription, bool Isadd)
        {
            // Logger.Prompt($"/*\n发起新订阅 : {user_subscription.SubscriptionString}");
            // 添加或者删除PushJob到队列
            lock (ActivePushJobLock)
            {
                if (Isadd)
                {
                    AddActivePushJob(user_subscription.PushJob);
                }
                else
                {
                    bool removed = RemoveActivePushJob(user_subscription.PushJob);
                    if (removed)
                    {
                        return;
                    }
                }
            }
        }

        private void AddActiveRequest(DataRequest request)
        {
            ActiveRequests.TryAdd(request.id, request);
            //SendRequestTotalCount++;
        }
        private void RemoveActiveRequest(DataRequest request)
        {
            ActiveRequests.TryRemove(request.id, out var req);
        }

        private DataRequest FindActiveRequest(DataResponse response)
        {
            ActiveRequests.TryGetValue(response.id, out var sent_request);
            return sent_request;

        }

        private bool AddActivePushJob(DataPushJob push_job)
        {
            bool bSub = false;
            if (!ActivePushJobs.ContainsKey(push_job.Subscription.Topic))
            {
                bSub = true;
                ActivePushJobs.Add(push_job.Subscription.Topic, new List<DataPushJob>());
            }
            ActivePushJobs[push_job.Subscription.Topic].Add(push_job);
            return bSub;
        }
        private bool RemoveActivePushJob(DataPushJob push_job)
        {
            ActivePushJobs.TryGetValue(push_job.Subscription.Topic, out var push_jobs);
            if (push_jobs.Count == 0)
            {
                return true;
            }
            push_jobs.Remove(push_job);
            return false;
        }
        private List<DataPushJob> FindActivePushJobs(DataResponse response)
        {
            return FindActivePushJobs(response.Topic);
        }
        private List<DataPushJob> FindActivePushJobs(string shared_instance_key)
        {
            if (string.IsNullOrEmpty(shared_instance_key))
            {
                return null;
            }
            ActivePushJobs.TryGetValue(shared_instance_key, out var push_jobs);
            return push_jobs;
        }


        private ConcurrentDictionary<Guid, DataRequest> ActiveRequests { get; } = new ConcurrentDictionary<Guid, DataRequest>();

        private Dictionary<string, List<DataPushJob>> ActivePushJobs { get; } = new Dictionary<string, List<DataPushJob>>();

        private object ActivePushJobLock { get; } = new object();

    }

    public delegate void PushedEventHandler<DataResponseT>(DataPushJob pushJob, DataResponseT data_response);
}
